/**
 * 构建视图数据
 * @param {*原生的课程分类集合} rawLabels
 * @param {*原生的课程集合} rawCourses
 * @param {*是否创建空白行，空白行主要提供添加课程按钮} isCreateBlankRow
 * @param {*是否空课程}
 * @return 包括新课程集合，总计学分，总计学时，课程分类的动态数
 */
function build(
    rawLabels,
    rawCourses,
    isCreateBlankRow = false,
    isEmptyCourse = false,
    isGraduate = false
) {
    if (isEmptyCourse) {
        rawCourses.length = 0;
    }
    let resultLabel = buildLabels(rawLabels);
    let resultCourse = buildCourses(
        resultLabel.leafLabel,
        rawCourses,
        isCreateBlankRow
    );
    let obj = buildTotal(resultCourse, resultLabel.tableDynamicColNum, isCreateBlankRow, isGraduate);
    return {
        tableDynamicColNum: resultLabel.tableDynamicColNum, //* 最大列数
        courses: obj.courses, //* 课程，用于绘制行
        totalScore: obj.totalScore, //* 总学分
        totalTime: obj.totalTime //* 总学时
    };
}
/**
 * 构建课程分类
 * @param {*原生的课程分类集合} rawLabels
 * @return 返回所有叶级课程分类
 */
function buildLabels(rawLabels) {
    // 叶级课程分类
    let parentId = rawLabels.filter(label => {
        return rawLabels.some(l => l.parentId == label.labelId);
    });
    // if (parentId.length > 0) {
    //     parentId.forEach(d => {
    //         rawLabels.forEach(label => {
    //             if (d.labelId == label.parentId) {
    //                 label.orderNo = d.orderNo + '.' + label.orderNo;
    //             }
    //         })
    //     })
    // }
    if (parentId.length > 0) {
        parentId.forEach(d => {
            if (d.label == "学位课" || d.label == "Degree Course") {
                d.idNoS = 1;
            }
        })
    }
    let leafLabel = rawLabels.filter(label => {
        return !rawLabels.some(l => l.parentId == label.labelId);
    });
    leafLabel.forEach(label => {
        label.labelMap = [
            {
                id: label.labelId,
                name: label.label || label.labelEn
            }
        ]; // 保存self,(另外数组维护有序的parent)
        label.ids = label.labelId; // 保存self的id,(另外数组维护有序的parent id)
        //label.idNoS = label.id;
        if (label.labelId == 999999) {
            label.idNoS = 999999999;
        } else {
            if (label.label == "公共学位课" || label.label == "Common Course") {
                label.idNoS = "2";
            }
            else if (label.label == "专业学位课" || label.label == "Core Course") {
                label.idNoS = "3";
            }
            else if (label.label == "非学位课" || label.label == "Elective Course") {
                label.idNoS = "4";
            }
            else if (label.label == "必修环节" || label.label == "Compulsories") {
                label.idNoS = "5";
            }
            else if (label.label == "补修课" || label.label == "Complementary Course") {
                label.idNoS = "6";
            }
            //label.idNoS = label.orderNo;
        }
        label.courseNum = 0;

        calcRootLabel(label, label, rawLabels);
    });
    // 根据ids层级排序，为合并行作准备
    leafLabel.sort((x, y) => {
        if (x.idNoS < y.idNoS) {
            return -1;
        } else if (x.idNoS > y.idNoS) {
            return 1;
        } else {
            return 0;
        }
    });
    let tableDynamicColNum = getDynamicColumnNum(leafLabel);
    return {
        leafLabel,
        tableDynamicColNum
    };
}
/**
 * 根据课程分类构建有序的课程列表
 * @param {* 叶级分类，由课程分类处理后获得} leafLabels
 * @param {* 原始课程集合} rawCourses
 * @param {* 是否创建空行空白行} isCreateBlankRow
 */
function buildCourses(leafLabels, rawCourses, isCreateBlankRow) {
    let cloneCourses = _.cloneDeep(rawCourses);
    let result = {
        labels: leafLabels //* 叶子label
    };
    cloneCourses.forEach(course => {
        let label = leafLabels.find(leaf => leaf.labelId == course.labelId);
        if (label) {
            course.label = _.cloneDeep(label);
            course.type = 'row';
            label.courseNum++; //* 叶子label行数
            course.newId = label.id;
        }
    });
    if (isCreateBlankRow) {
        // 无课程的分类构造空行
        leafLabels.forEach(label => {
            if (label.courseNum == 0) {
                cloneCourses.push({
                    type: 'blank',
                    label: label,
                    labelId: label.labelId
                });
            }
        });
    }
    // 过滤无课程分类的课程,再根据课程分类层级排序所有课程
    //* 升序排序后的课程（包含没有子类的大类占一行），这个是关键数组用于绘制行
    result.courses = cloneCourses
        .filter(course => course.label != null)
        .sort((x, y) => {
            if (x.label.idNoS < y.label.idNoS) {
                return -1;
            } else if (x.label.idNoS > y.label.idNoS) {
                return 1;
            } else {
                return 0;
            }
        });
    // 标记分类的末尾课程
    leafLabels.forEach(label => {
        //* 同一个label下的课程
        let labelCourses = result.courses.filter(
            c => c.labelId == label.labelId && c.type == 'row'
        );
        if (labelCourses.length > 0) {
            _.each(labelCourses, c => {
                c.isLast = false;
            });
            let code = labelCourses[labelCourses.length - 1].code;
            let course = _.findLast(result.courses, c => c.code === code);
            if (course) {
                course.isLast = true; //* 标识课程是否是某个label下的末尾课程
            }
        }
    });
    return result;
}
/**
 * 构建总学分总学时、分类跨列数
 * @param {*} data
 * @param {*} tableDynamicColNum
 */
function buildTotal(data, tableDynamicColNum, isCreateBlankRow, isGraduate) {
    let totalScore = 0;
    let totalTime = 0;
    if (!isCreateBlankRow) {
        data.courses.forEach(course => {
            if (course.type == 'row') {
                totalScore += +course.credits;
                totalTime += +course.period;
            }
        });
    } else {
        data.courses.forEach(course => {
            if (course.type == 'row' && (course.selected || isGraduate) || course.labelId === 999999) {
                totalScore += +course.credits;
                totalTime += +course.period;
            }
        });
    }

    data.totalScore = totalScore; //* 总学分
    data.totalTime = totalTime; //* 总学时
    calcLabelRowspan(data.labels, data.courses, tableDynamicColNum);
    return data;
}
/**
 * 计算每个课程分类的跨列数和跨列数
 * @param {*} labels
 * @param {*} courses
 * @param {*} tableDynamicColNum
 */
function calcLabelRowspan(labels, courses, tableDynamicColNum) {
    let labelIds = []; //* 存放每个叶子label 的id和行数的数组
    labels.forEach(label => {
        let count = courses.filter(c => c.labelId == label.labelId).length; //* 如果没有真正的课程，则 course 包含当前label自己，courseNum是真正课程数量，count不一定，不会小于1
        labelIds.push({
            id: label.labelId,
            rowspan: count
        });
    });
    let processIds = []; //* 存放处理过行数的label id
    let courseGroupId = [];
    courses.forEach((course) => {
        course.label.labelMap.forEach((label, index) => {
            if (processIds.indexOf(label.id) == -1) {
                if (labelIds.some(l => l.id == label.id)) {
                    //* 如果是叶子label
                    //* 课程关联的label对象赋值行数
                    label.rowspan = labelIds.find(
                        l => l.id == label.id
                    ).rowspan;
                } else {
                    //* 非叶子label时
                    let ralationCourses = courses.filter(
                        c =>
                            c.label.ids.indexOf(label.id + ',') == 0 ||
                            c.label.ids.indexOf(',' + label.id + ',') > 0
                    );
                    //* 非叶子label行数=相关课程数量
                    label.rowspan = ralationCourses.length;
                }
                //* 处理过的label id 放到这个数组
                processIds.push(label.id);
            } else {
                //* 与首位课程中 label 重复的label
                label.rowspan = 0;
            }
            // 计算每个分类跨列数
            if (course.label.labelMap.length == tableDynamicColNum) {
                //* 当labelMap元素数量等于最大列数
                label.colspan = 1; //* 每个 label 占一列
            } else {
                //* 如果不是最后一级label则只占一列，否则colspan = 最大列数-index  0 1 2 (3-2=1,3-1=2,3-0=3)
                label.colspan =
                    index < course.label.labelMap.length - 1
                        ? 1
                        : tableDynamicColNum - index;
            }
        });
        //几选几合并单元格
        if (course.courseGroupId) {
            if (courseGroupId.indexOf(course.courseGroupId) == -1) {
                let ralationCourses = courses.filter(
                    c =>
                        c.courseGroupId == course.courseGroupId
                );
                //* 非叶子label行数=相关课程数量
                course.colspan = ralationCourses.length;
                courseGroupId.push(course.courseGroupId);
            } else {
                //* 与首位课程中 label 重复的label
                course.colspan = 0;
            }
        } else {
            course.colspan = 1
        }
    });
}
/**
 * 递归计算每个叶级的根
 * @param {*} currentLabel
 * @param {*} leafLabel
 * @param {*原始分类集合} leafLabels
 */
function calcRootLabel(currentLabel, leafLabel, rawLabels) {
    let parentLabel = rawLabels.find(
        label => label.labelId == currentLabel.parentId
    );
    if (parentLabel) {
        leafLabel.labelMap.unshift({
            id: parentLabel.labelId,
            name: parentLabel.label
        });
        leafLabel.ids = parentLabel.labelId + ',' + leafLabel.ids;
        if (parentLabel.parentId != 0) {
            calcRootLabel(parentLabel, leafLabel, rawLabels);
        }
    }
}
/**
 * 获取动态列数
 * @param {*} leafLabels
 */
function getDynamicColumnNum(leafLabels) {
    let num = 1;
    leafLabels.forEach(c => {
        if (num < c.labelMap.length) {
            num = c.labelMap.length;
        }
    });
    return num;
}

/**
 * 验证所有规则
 * 1.培养方案类别学分验证
 * 2.培养方案分类总学分验证
 * 3.模板规则验证
 * 4.第一外语验证
 * 5.分组与分模块验证
 *
 * @param {*} rawLabels
 * @param {*} courses
 * @param {*} rawRules
 * @param {*} foreigns
 * @param {*} cultureCourseLabelRelationList
 * @param {*} categoryTotalScore
 * @param {*} trainingCategoryCode
 */
function validate(
    rawLabels,
    courses,
    rawRules,
    foreigns,
    cultureCourseLabelRelationList,
    categoryTotalScore,
    trainingCategoryCode,
    degreeType
) {
    let notRequireValidatDegreeTypes = ["无学位"];//学位类型为"无学位"的学生制定培养方案时，不受系统模板学分要求限制
    // let notRequireValidations = [6, 4, 7];//培养类别为“课程进修生6”或“旁听生4”“研修生7”的学生制定培养方案时，不受系统模板学分要求限制
    let isRequire = notRequireValidatDegreeTypes.findIndex(e => e == degreeType) === -1;
    // let isRequire = notRequireValidations.findIndex(e => e == +trainingCategoryCode) === -1;
    let result = validateScore(rawLabels, courses, isRequire);
    if (!result.success) {
        return result;
    }
    result = validateTotalScore(courses, categoryTotalScore, isRequire);
    if (!result.success) {
        return result;
    }

    // TODO:模板规则验证，依赖四大课程

    result = validateForeign(foreigns, courses);
    if (!result.success) {
        return result;
    }
    result = validateAllGroup(
        courses,
        rawLabels,
        cultureCourseLabelRelationList
    );
    return result;
}

/**
 * 培养方案类别学分验证
 * @param {*原始课程分类集合} rawLabels
 * @param {*新课程集合} course
 * @param {*新课程集合} isRequire //是否需要校验
 */
function validateScore(rawLabels, courses, isRequire) {
    let result = {
        success: true,
        errors: []
    };
    if (isRequire) {
        let lableOne;
        let lableTwo;
        lableOne = _.sumBy(courses.filter(c => c.type == 'row' && c.labelId == 999999), c => c.credits);
        rawLabels
            .forEach(label => {
                let fn = null;
                let score = 0;
                if (label.parentId == 0) {
                    fn = c => c.type == 'row' && (c.labelId == label.labelId);
                } else {
                    fn = c =>
                        c.type == 'row' &&
                        (c.label.ids == label.parentId + ',' + label.labelId ||
                            c.label.ids.indexOf(
                                label.parentId + ',' + label.labelId + ','
                            ) == 0);
                }
                score = _.sumBy(courses.filter(fn), c => c.credits);
                if (label.label == "非学位课") {
                    score = score + lableOne
                    if (label.credit > score) {
                        result.success = false;
                        result.errors.push({
                            type: 'score',
                            score: score,
                            name: label.label,
                            credit: label.credit
                        });
                    }
                } else {
                    if (label.credit > score) {
                        result.success = false;
                        result.errors.push({
                            type: 'score',
                            score: score,
                            name: label.label,
                            credit: label.credit
                        });
                    }
                }
            });
    }
    return result;
}
/**
 * 模板规则验证
 * @param {*规则列表} rawRules
 * @param {*新课程集合} courses
 */
function validateCourseLimit(rawRules, courses) {
    let result = {
        success: true,
        errors: []
    };
    rawRules
        .filter(label => label.totalNum != '' && label.optional != '')
        .forEach(label => {
            let fn = null;

            let courseNum = 0;
            if (label.pid == 0) {
                fn = c => c.type == 'row' && c.labelId == label.labelId;
            } else {
                fn = c =>
                    c.type == 'row' &&
                    (c.label.ids == label.pid + ',' + label.labelId ||
                        c.label.ids.indexOf(
                            label.pid + ',' + label.labelId + ','
                        ) == 0);
            }
            courseNum = _.sumBy(courses.filter(fn), c => 1);
            if (courseNum < label.optional || courseNum > label.totalNum) {
                result.success = false;
                result.errors.push({
                    type: 'num',
                    num: courseNum,
                    name: label.name,
                    maxNum: label.totalNum,
                    minNum: label.optional
                });
            }
        });
    return result;
}
/**
 * 第一外国语验证
 * @param {*第一外国语规则集合} foreigns
 * @param {*新课程集合} courses
 */
function validateForeign(foreigns, courses) {
    let result = {
        success: true,
        errors: []
    };
    let sum = 0;
    if (foreigns && foreigns.length > 0) {
        //处理多个
        foreigns.forEach(d => {
            //let courseCodes = d.courseCode.split(","); // 当前大课号对应的小课号
            //let maxNumber = d.maxNumber; // 小课号最大数

            let findCourse = [];
            // 查找小课号的匹配数量
            courses.forEach(code => {
                if (code.code == d) {
                    if (code.selected) {
                        sum = 2
                    }
                }
            });
        });
        if (sum < 2) {
            result.success = false;
            result.errors.push({
                type: "foreign",
            });
        }
    }
    return result;
}
// function validateForeign(foreigns, courses) {
//     let result = {
//         success: true,
//         errors: []
//     };
//     if (foreigns && foreigns.length > 0) {
//         //处理多个
//         foreigns.forEach(d => {
//             let courseCodes = d.courseCode.split(","); // 当前大课号对应的小课号
//             let maxNumber = d.maxNumber; // 小课号最大数
//             let sum = 0;
//             let findCourse = [];
//             // 查找小课号的匹配数量
//             courseCodes.forEach(code => {
//                 let smallCourseCode = courses.find(c => c.code == code);
//                 if (smallCourseCode) {
//                     sum++;
//                     findCourse.push(code);
//                 }
//             });
//             if (sum > maxNumber) {
//                 result.success = false;
//                 result.errors.push({
//                     type: "foreign",
//                     rulesCode: d.courseCode,
//                     findCode: findCourse.join(","),
//                     maxNumber: maxNumber
//                 });
//             }
//         });
//     }
//     return result;
// }
/**
 * 验证分组
 * @param {*} rawCourses
 * @param {*} rawLabels
 * @param {*} cultureCourseLabelRelationList
 */
function validateAllGroup(
    rawCourses,
    rawLabels,
    cultureCourseLabelRelationList
) {
    let result = {
        success: true,
        errors: []
    };
    result = validateSmallGroup(
        rawCourses.filter(
            c => c.type == 'row' && c.courseGroupId && c.parentId == null
        ),
        null,
        null,
        cultureCourseLabelRelationList,
        rawLabels
    );
    result = validateBigGroup(rawLabels, rawCourses, cultureCourseLabelRelationList) && result;
    return result;
}
/**
 * 根据培养方案，验证小分组
 * @param courses 当前选中课程
 * @param parentId 大分组id
 * @param courseGroupId 小分组id
 * @param cultureCourseLabelRelationList 培养方案课程与分类关系，包含所有的分组信息
 * @param rawLabels 原始课程分类
 */
function validateSmallGroup(
    courses,
    parentId = null,
    courseGroupId = null,
    cultureCourseLabelRelationList,
    rawLabels
) {
    let result = {
        success: true,
        errors: []
    };
    const LIMIT_TYPE = {
        number: 0,
        credits: 1
    }; // 0为限制门数，1为限制学分
    const EXPRESSION = {
        greaterEqual: 1,
        equal: 2
    }; // 1为大于等于，2为等于
    let groups = []; // 所有分组信息
    let fn = c => {
        if (!groups.find(g => g.groupId == c.courseGroupId)) {
            groups.push({
                groupId: c.courseGroupId,
                groupRemark: c.groupRemark,
                chooseNum: c.chooseNum,
                totalNum: c.totalNum,
                expression: c.expression,
                maxNum: c.maxNum,
                minNum: c.minNum,
                type: c.type,
                minCredits: c.minCredits,
                parentRemark: c.parentRemark
            });
        }
    };
    if (courseGroupId) {
        cultureCourseLabelRelationList
            .filter(
                c => c.courseGroupId == courseGroupId && c.parentId == parentId
            )
            .forEach(fn);
    } else {
        cultureCourseLabelRelationList
            .filter(c => c.courseGroupId && c.parentId == null)
            .forEach(fn);
    }
    groups.forEach(group => {
        let match = true;
        let match2 = true;
        let error = null;
        if (group.type == LIMIT_TYPE.number) {
            // 限制门数
            let chooseNum = 0;
            courses.forEach(c => {
                if (c.courseGroupId == group.groupId) {
                    chooseNum++;
                }
            });
            if (group.expression == 2) {
                if (chooseNum != group.maxNum) {
                    match2 = false;
                }
            } else {
                if (chooseNum > group.maxNum || chooseNum < group.minNum) {
                    match = false;
                }
                // console.log(chooseNum)
                // console.log(group.maxNum)
                // console.log(group.minNum)
                // if (chooseNum < group.minNum) {
                //     match = false;
                // }
            }
            if (!match2) {
                error = {
                    type: 'groupNums',
                    actNum: chooseNum,
                    groupRemark: group.groupRemark,
                    maxNum: group.maxNum,
                };
            }
            if (!match) {
                error = {
                    type: 'groupNum',
                    actNum: chooseNum,
                    groupRemark: group.groupRemark,
                    maxNum: group.minNum,
                };
            }
        } else {
            // 限制学分
            let credits = 0;
            courses.forEach(c => {
                if (c.courseGroupId == group.groupId) {
                    credits += c.credits;
                }
            });
            match =
                group.expression == EXPRESSION.greaterEqual
                    ? credits >= group.minCredits
                    : credits == group.minCredits;
            if (!match) {
                error = {
                    type: 'groupCredits',
                    actNum: credits,
                    groupRemark: group.groupRemark,
                    minNum: group.minCredits,
                    expression:
                        group.expression == EXPRESSION.greaterEqual
                            ? '大于等于'
                            : '等于'
                };
            }
        }
        if (!match || !match2) {
            result.success = false;
            let course = cultureCourseLabelRelationList.find(
                c => c.courseGroupId == group.groupId
            );
            let label = rawLabels.find(l => l.labelId == course.labelId);
            error.label = label.label;
            error.labelEn = label.labelEn;
            error.parentRemark = group.parentRemark;
            result.errors.push(error);
        }
    });
    return result;
}
/**
 * 根据培养方案验证大分组
 * @param {*} rawLabels
 * @param {*} courses
 * @param {*} cultureCourseLabelRelationList
 */
function validateBigGroup(rawLabels, courses, cultureCourseLabelRelationList) {
    let result = {
        success: true,
        errors: []
    };
    let groups = [];
    cultureCourseLabelRelationList
        .filter(c => c.courseGroupId && c.parentId)
        .forEach(c => {
            if (!groups.find(g => g.parentId == c.parentId)) {
                groups.push({
                    parentId: c.parentId,
                    parentRemark: c.parentRemark,
                    chooseNum: c.parentChooseNum,
                    totalNum: c.parentTotalNum,
                    pid: c.labelId
                });
            }
        });
    groups.forEach(group => {
        let ids = [];
        courses
            .filter(c => c.parentId == group.parentId)
            .forEach(c => {
                if (ids.indexOf(c.courseGroupId) == -1) {
                    ids.push(c.courseGroupId);
                }
            });
        if (ids.length != group.chooseNum) {
            let label = rawLabels.find(l => l.id == group.pid);
            result.success = false;
            result.errors.push({
                type: 'bigGroup',
                actNum: ids.length,
                planNum: group.chooseNum,
                totalNum: group.totalNum,
                groupRemark: group.parentRemark,
                label: label.name,
                labelEn: label.nameEn
            });
        } else {
            if (ids.length == 0) {
                // todo:培养方案分组设置错误
            } else {
                ids.forEach(id => {
                    result =
                        validateSmallGroup(
                            courses.filter(c => c.courseGroupId == id),
                            group.parentId,
                            id,
                            cultureCourseLabelRelationList,
                            rawLabels
                        ) && result;
                });
            }
        }
    });
    return result;
}

/**
 * 验证培养方案分类总分
 * @param {*} course
 * @param {*} categoryTotalScore
 * @param {*} isRequire //是否需要校验
 */
function validateTotalScore(courses, categoryTotalScore, isRequire) {
    let result = {
        success: true,
        errors: []
    };
    if (isRequire) {
        let sum = _.sumBy(courses, c => c.credits);
        if (sum < categoryTotalScore) {
            result.success = false;
            result.errors.push({
                type: 'categoryTotalScore',
                actNum: sum,
                planNum: categoryTotalScore
            });
        }

    }
    return result;
}
const PLAN_STATUS = {
    none: -1,
    draft: 0,
    checking: 1,
    reject: 2,
    pass: 3
};
export { build, validate, PLAN_STATUS };

